#include "batcher.h"
#include "irenderer.h"
#include "ieffect.h"

namespace gecko
{

	VertexCache::VertexCache()
		: m_VertexBuffer(NULL)
		, m_IndexBuffer(NULL)
		, m_VertexCount(0)
		, m_IndexCount(0)
		, m_VertsPerPrimitive(1)
	{

	}

	bool VertexCache::Initialise(IRenderer* renderer)
	{
		m_VertexBuffer = renderer->CreateVertexBuffer(HARD_VERTEX_LIMIT, true);
		m_IndexBuffer = renderer->CreateIndexBuffer(HARD_VERTEX_LIMIT, true);
		return true;
	}

	void VertexCache::Begin( IVertexBuffer::ePrimitiveType primitiveType )
	{
		m_PrimitiveType = primitiveType;

		/*switch ( primitiveType )
		{
		case IVertexBuffer::PT_TRIANGLELIST:
			m_VertsPerPrimitive = 3;
			break;

		case IVertexBuffer::PT_LINELIST:
			m_VertsPerPrimitive = 2;
			break;

		case IVertexBuffer::PT_TRIANGLEFAN:
			m_VertsPerPrimitive = 

		default:
			FSError("Unsupported primitive type");
			break;
		}*/

		m_VertexCount = 0;
		m_NumDrawCalls = 0;

		m_VertexBuffer->Lock(0, HARD_VERTEX_LIMIT, &m_Vertices);
		m_IndexBuffer->Lock(0, HARD_VERTEX_LIMIT, &m_Indices);
	}

	void VertexCache::Flush()
	{
		m_VertexBuffer->Unlock();
		m_IndexBuffer->Unlock();

		int primitiveCount = 0;

		switch (m_PrimitiveType)
		{
		case IVertexBuffer::PT_POINTLIST:
			primitiveCount = m_IndexCount ? m_IndexCount : m_VertexCount;
			break;
		case IVertexBuffer::PT_LINELIST:
			primitiveCount = m_IndexCount ? m_IndexCount / 2 : m_VertexCount / 2;
			break;
		case IVertexBuffer::PT_LINESTRIP:
			break;
		case IVertexBuffer::PT_TRIANGLELIST:
			primitiveCount = m_IndexCount ? m_IndexCount / 3 : m_VertexCount / 3;
			break;
		case IVertexBuffer::PT_TRIANGLESTRIP:
			break;
		}

		//int primitiveCount = m_IndexCount ? (m_IndexCount / m_VertsPerPrimitive) : (m_VertexCount / m_VertsPerPrimitive);

		if ( primitiveCount > 0 )
		{
			//mDevice.Textures[0] = mContext.Texture1;
			//mDevice.Textures[1] = mContext.Texture2;

			if ( m_IndexCount )
			{
				m_VertexBuffer->SetIndexBuffer(m_IndexBuffer);
				m_VertexBuffer->RenderIndexed(m_PrimitiveType, m_IndexCount, primitiveCount);
			}
			else
			{
				m_VertexBuffer->Render(m_PrimitiveType, primitiveCount);
			}
			++m_NumDrawCalls;
		}

		m_VertexCount = 0;
		m_IndexCount = 0;
	}

	void VertexCache::End()
	{
		Flush();
	}

	void VertexCache::AddVertex( const Vertex& vertex )
	{
		if ( m_VertexCount > HARD_VERTEX_LIMIT )
		{
			Flush();
			Begin(m_PrimitiveType);
		}

		m_Vertices[m_VertexCount].Position = vertex.Position;
		m_Vertices[m_VertexCount].Colour = vertex.Colour;

		m_VertexCount++;
	}

	void VertexCache::AddGeometry( GeometryInstance& instance )
	{
		Geometry* geometry = instance.m_Geometry;

		if (m_IndexCount + geometry->m_numIndices > HARD_VERTEX_LIMIT)
		{
			Flush();
			Begin(m_PrimitiveType);
		}

		Vertex* vertBuffer = (m_Vertices + m_VertexCount);
		unsigned short* indexBuffer = (m_Indices + m_IndexCount);

		if ( instance.m_Type == GeometryInstance::Type_Static )
		{
			for ( unsigned short i = 0; i < geometry->m_numVertices; i++ )
			{
				vertBuffer[i].Position, geometry->m_vertices[i].Position;
				vertBuffer[i].Colour = geometry->m_vertices[i].Colour;
				vertBuffer[i].Tu = geometry->m_vertices[i].Tu;
				vertBuffer[i].Tv = geometry->m_vertices[i].Tv;
			}
		}
		else
		{
			for ( unsigned short i = 0; i < geometry->m_numVertices; i++ )
			{
				// transform vertex fully
				VectorMultiply(vertBuffer[i].Position, geometry->m_vertices[i].Position, static_cast<DynamicGeometryInstance&>(instance).Tranform);

				vertBuffer[i].Colour = geometry->m_vertices[i].Colour;
				vertBuffer[i].Tu = geometry->m_vertices[i].Tu;
				vertBuffer[i].Tv = geometry->m_vertices[i].Tv;
			}
		}

		for ( unsigned short i = 0; i < geometry->m_numIndices; i++ )
		{
			indexBuffer[i] = geometry->m_indices[i] + m_VertexCount;
		}

		m_VertexCount += geometry->m_numVertices;
		m_IndexCount += geometry->m_numIndices;
	}

}

